////////////////////////////////////////////////////////////////////////////////

#ifndef _CLIENTGUI_H_
#define _CLIENTGUI_H_

////////////////////////////////////////////////////////////////////////////////

#ifndef _GRAPHICS_H_
#include "graphics.h"
#endif

#ifndef _INPUT_H_
#include "input.h"
#endif

#ifndef _CLIENTINPUT_H_
#include "clientinput.h"
#endif

#ifndef _MUTEX_H_
#include "mutex.h"
#endif

#ifndef _CLIENTBATTLEFIELD_H_
#include "clientbattlefield.h"
#endif

#ifndef _SERVERSTATE_H_
#include "serverstate.h"
#endif

#include <queue>

////////////////////////////////////////////////////////////////////////////////

class Client;
class ServerStatePacket;
class ClientInputPacket;

////////////////////////////////////////////////////////////////////////////////


/** Client GUI and INPUT
*
*
*  @author   Roman Pasechnik
*  @since    Jun 11th, 2009
*  @updated  Nov 12th, 2009
*/
class ClientGUI : public Observer
{
////////////////////////////////////////////////////////////////////////////////

public:

////////////////////////////////////////////////////////////////////////////////


    /** Constructor */
    ClientGUI();
    
    
    /** Destructor */
    ~ClientGUI();

    
////////////////////////////////////////////////////////////////////////////////


    /** Start GUI */
    void Start( Client* _client );


////////////////////////////////////////////////////////////////////////////////


    /** Get client input */
    const ClientInput& GetClientInput() const;
 

////////////////////////////////////////////////////////////////////////////////


    /** Render server state */
    void Render();


    /** Add data to render queue */
    void AddStateToRenderQueue( const ServerStatePacket& _packet );


////////////////////////////////////////////////////////////////////////////////


    /** Set client ID */
    void SetID( int _ID );


    /** Create battlefield map */
    void CreateMap( const std::string& _mapName );


////////////////////////////////////////////////////////////////////////////////

private:    
    
////////////////////////////////////////////////////////////////////////////////
//// Observer interface implementation
////////////////////////////////////////////////////////////////////////////////


    /** Notify observer about event */
    virtual void OnEvent( Event _event, Observable* _observable );


////////////////////////////////////////////////////////////////////////////////


    /** Key change handler */
    void OnKeyChanged();


    /** Mouse position change handler */
    void OnMousePositionChanged();


////////////////////////////////////////////////////////////////////////////////


    /** Load images */
    void LoadImages();


    /** Start game loop */
    void RunGameLoop();


////////////////////////////////////////////////////////////////////////////////


    /** Every time we perform a render, we have to draw server state on the screen.
    Server packets with that state come to client ~30 times per second.
    Rendering could be much faster, for example 100 times per second.
    Thats why we need to integrate between those 30 states to get 100 states.
    We always integrate between 2 states to get one INTERMEDIATE state. */


    /** First state being integrated */
    ServerState m_FirstState;


    /** Second state being integrated */
    ServerState m_SecondState;


    /** Integration coefficient, telling where exactly 
    we are between first and second ServerState.
    If it is 0 - we are exactly at first state,
    if it is 1 - we are exactly at first second state,
    if it is 0.5 - we are exactly between first and second state */
    double m_FirstToSecondCoeff;


////////////////////////////////////////////////////////////////////////////////


    /** Fetches first and second states and saves a coefficient.
    Returns true if fetching have been done successfully
    and render should be performed. */
    bool FetchTwoStatesAndCoeff();


    /** Render battlefield */
    void RenderBattlefield();


    /** Draw FPS */
    void DrawFPS();


////////////////////////////////////////////////////////////////////////////////


    /** Graphics */
    Graphics m_Graphics;


    /** Player image */
    Graphics::Object m_Player;


    /** Bullet image */
    Graphics::Object m_Bullet;


    /** Wall image */
    Graphics::Object m_Wall;


    /** Heart image */
    Graphics::Object m_Heart;


    /** Background image */
    Graphics::Object m_Background;



////////////////////////////////////////////////////////////////////////////////


    /** Input */
    Input m_Input;


    /** Process input events */
    void ProcessInput();


////////////////////////////////////////////////////////////////////////////////


    /** [Utility type]: Battlefield state and time of its creation */
    typedef std::pair<size_t, ServerState> RenderState;


    /** [Utility type]: Queue of render states */
    class RenderQueue : public std::deque<RenderState>, public Mutex {};


    /** Render queue */
    RenderQueue m_RenderQueue;


    /** Client input */
    ClientInput m_ClientInput;


    /** Client interface */
    Client* m_Client;


    /** Client battlefield */
    ClientBattlefield m_Battlefield;


    /** Stop game? */
    bool m_Stop;


    /** Client ID */
    int m_ID;


////////////////////////////////////////////////////////////////////////////////
};


////////////////////////////////////////////////////////////////////////////////

#endif

////////////////////////////////////////////////////////////////////////////////

